module wr_datas #(parameter WR_LENTH = 3)(
    input               clk         ,
    input               rst_n       ,
    output              skipidle    ,
    //---------<rx>------------------------------------------------- 
    input     [7:0]     rx_data     ,
    input               rx_vld      ,
    //---------<key>------------------------------------------------- 
    input     [2:0]     key_down    ,
    //---------<fifo>------------------------------------------------- 
    output    [5:0]     usedw       ,     
    //---------<spi_driver>------------------------------------------------- 
    input               trans_done  ,
    input     [7:0]     rd_data     ,
    output              rw_flag     ,
    output    reg [7:0] wr_data     
);

reg     [2:0]   state_c ;
reg     [2:0]   state_n ;

localparam      IDLE    =   3'd0,
                WREN    =   3'd1,
                DELAY1  =   3'd2,
                SE      =   3'd3,
                PP      =   3'd4,
                DELAY2  =   3'd5,
                RDSR    =   3'd6;

wire        IDLE_2_WREN     ;
wire        WREN_2_DELAY1   ;
wire        DELAY1_2_PP     ;
wire        DELAY1_2_SE     ;
wire        PP_2_DELAY2     ;
wire        SE_2_DELAY2     ;
wire        DELAY2_2_RDSR   ;
wire        RDSR_2_IDLE     ;

wire        rdreq           ;
wire        wrreq           ;
wire        empty           ;
wire        full            ;
wire  [7:0] q               ;

reg	  [5:0] cnt_delay	    ;
wire		add_cnt_delay   ;
wire		end_cnt_delay   ;
reg         op_flag         ;

reg		[8:0]	cnt_byte	;
wire			add_cnt_byte;
wire			end_cnt_byte;

reg		[23:0]	wr_addr;
wire			add_wr_addr ;
wire			end_wr_addr ;

reg             rdsr_flag   ;   //读状态寄存器写传输标志1为在写，为0在读

//---------<fifo>------------------------------------------------- 

fifo	fifo_inst (
	.aclr       ( ~rst_n    ),
	.clock      ( clk       ),
	.data       ( rx_data   ),
	.rdreq      ( rdreq     ),
	.wrreq      ( wrreq     ),
	.empty      ( empty     ),
	.full       ( full      ),
	.q          ( q         ),
	.usedw      ( usedw     )
	);

assign wrreq    =   ~full && rx_vld;
assign rdreq    =   ~empty && (state_c == PP) && (cnt_byte >= 4) && trans_done;

//---------<cnt_delay>------------------------------------------------- 

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_delay <= 'd0;
    end 
    else if(add_cnt_delay)begin 
        if(end_cnt_delay)begin 
            cnt_delay <= 'd0;
        end
        else begin 
            cnt_delay <= cnt_delay + 1'b1;
        end 
    end
end 

assign add_cnt_delay = ((state_c == DELAY1) || (state_c == DELAY2));
assign end_cnt_delay = add_cnt_delay && cnt_delay == 50-1;

//---------<op_flag>------------------------------------------------- 

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        op_flag <= 1'd0;
    end 
    else if(key_down[2])begin 
        op_flag <= 1'd1;
    end 
    else if(usedw >= 3)begin 
        op_flag <= 1'd0;
    end 
end

//---------<cnt_byte>------------------------------------------------- 

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_byte <= 'd0;
    end 
    else if(add_cnt_byte)begin 
        if(end_cnt_byte)begin 
            cnt_byte <= 'd0;
        end
        else begin 
            cnt_byte <= cnt_byte + 1'b1;
        end 
    end
end 

assign add_cnt_byte = ((state_c == SE) || (state_c == PP)) && trans_done;
assign end_cnt_byte = add_cnt_byte && cnt_byte == ((state_c == SE) ? (4-1) : (4+WR_LENTH-1));

//---------<wr_addr>------------------------------------------------- 

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        wr_addr <= 24'h02_00_00;
    end 
    else if(add_wr_addr)begin 
        if(end_wr_addr)begin 
            wr_addr <= 24'h02_00_00;
        end
        else begin 
            wr_addr <= wr_addr + WR_LENTH;
        end 
    end
end 

assign add_wr_addr = PP_2_DELAY2;
assign end_wr_addr = add_wr_addr && wr_addr == 24'h1f_ff_ff;


//---------<state>------------------------------------------------- 

//第一段：同步时序描述状态转移
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        state_c <= IDLE;
    end 
    else begin 
        state_c <= state_n;
    end 
end
    
//第二段：组合逻辑判断状态转移条件，描述状态转移规律
always @(*) begin
    case(state_c)
        IDLE  : state_n = IDLE_2_WREN  ? WREN  : state_c ;
        WREN  : state_n = WREN_2_DELAY1? DELAY1: state_c ;
        DELAY1: state_n = DELAY1_2_PP  ? PP    : (DELAY1_2_SE ? SE : state_c);
        SE    : state_n = SE_2_DELAY2  ? DELAY2: state_c ;
        PP    : state_n = PP_2_DELAY2  ? DELAY2: state_c ;
        DELAY2: state_n = DELAY2_2_RDSR? RDSR  : state_c ;
        RDSR  : state_n = RDSR_2_IDLE  ? IDLE  : state_c ;
        default : state_n = state_c;
    endcase
end

assign  IDLE_2_WREN  = (state_c == IDLE  ) &&   (key_down[2] || usedw >= WR_LENTH);
assign  WREN_2_DELAY1= (state_c == WREN  ) &&    trans_done ;
assign  DELAY1_2_PP  = (state_c == DELAY1) &&    end_cnt_delay   &&  !op_flag;
assign  DELAY1_2_SE  = (state_c == DELAY1) &&    end_cnt_delay   &&   op_flag;
assign  PP_2_DELAY2  = (state_c == PP    ) &&    end_cnt_byte;
assign  SE_2_DELAY2  = (state_c == SE    ) &&    end_cnt_byte;
assign  DELAY2_2_RDSR= (state_c == DELAY2) &&    end_cnt_delay;
assign  RDSR_2_IDLE  = (state_c == RDSR  ) &&    trans_done  &&  (rd_data[0] == 1'b0);

//---------<rdsr_flag>------------------------------------------------- 

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        rdsr_flag <= 1'b0;
    end 
    else if(DELAY2_2_RDSR)begin 
        rdsr_flag <= 1'b1;
    end 
    else if((state_c == RDSR) && trans_done)begin 
        rdsr_flag <= 1'b0;
    end 
end

//---------<wr_data>-------------------------------------------------

always @(*)begin 
    case(state_c)
        WREN  :  wr_data = 8'h06 ;
        SE    :  begin
            case(cnt_byte)
                0   :   wr_data = 8'hd8;
                1   :   wr_data = wr_addr[23:16];
                2   :   wr_data = wr_addr[15:8];
                3   :   wr_data = wr_addr[7:0];
                default : wr_data = 8'h00 ;   
            endcase
        end
        PP     :  begin
            case(cnt_byte)
                0   :   wr_data = 8'h02;
                1   :   wr_data = wr_addr[23:16];
                2   :   wr_data = wr_addr[15:8];
                3   :   wr_data = wr_addr[7:0];
                default : wr_data = q ;   
            endcase
        end
        RDSR  :  wr_data = rdsr_flag ? 8'h05 : 8'h00;
        default : wr_data = 8'd0;
    endcase
end

//---------<rw_flag>------------------------------------------------- 

assign  rw_flag = (state_c == WREN) || (state_c == SE) || (state_c == PP) || (state_c == RDSR);
assign  skipidle = RDSR_2_IDLE;

endmodule